home *** CD-ROM | disk | FTP | other *** search
- /************************** Start of CRCMAN.C *************************
- *
- * This program is used to build a list of CRC-32 values for all of the
- * files in a given directory tree. After building the file, the program
- * can be run later to verify the CRC values, giving assurance of the
- * integrity of the files. To build the CRC file, the command line is:
- *
- * CRCMAN -b root-dir crc-file-name
- *
- * To check the list of files created, run with this command line:
- *
- * CRCMAN crc-file-name
- *
- * This program should work with most 16 and 32 bit compilers under
- * MS-DOS and UNIX.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <sys/types.h>
- #include <sys/stat.h>
-
-
- unsigned long CRCTable[ 256 ];
-
- /*
- * To build this program under UNIX, define UNIX either on the command
- * line or by editing this file. To define it on the command line, the
- * program should be built like this:
- *
- * cc -o crcman -DUNIX crcman.c
- *
- * The code in this program assumes that the UNIX compiler is of the
- * K&R variety, and does away with real function prototyping.
- */
-
- #ifdef UNIX
-
- #include <varargs.h>
- #ifdef M_XENIX
- #include <sys/ndir.h>
- #else
- #include <sys/dirent.h>
- #endif /* M_XENIX */
-
- #define SEPARATOR "/"
- #define FILENAME_SIZE 81
-
- void FatalError();
- unsigned long CalculateFileCRC();
- void ProcessAllFiles();
- void BuildCRCFile();
- void CheckFiles();
- unsigned long CalculateBufferCRC();
- void BuildCRCTable();
-
- #else /* not UNIX, must be MSDOS */
- /*
- * Most MS-DOS compilers have converged on the same names for the
- * structures and functions used when searching directories.
- * Unfortunately, Borland C implementations still use a variant,
- * which requires a few macro definitions to work around. The
- * functions work in an identical manner, so the actual
- * implementation of the code is straightforward. The addition of
- * the MSDOS definition helps convince the Zortech compiler to use
- * the same structure and function names as everyone else.
- *
- */
-
- #define MSDOS 1
- #include <stdarg.h>
- #include <dos.h>
-
- #define SEPARATOR "\\"
- #define FILENAME_SIZE FILENAME_MAX
-
- #ifdef __TURBOC__
-
- #include <dir.h>
- #define FILE_INFO struct ffblk
- #define FIND_FIRST( n, i ) findfirst( ( n ), ( i ), FA_DIREC )
- #define FIND_NEXT( info ) findnext( ( info ) )
- #define FILE_NAME( info ) ( ( info ).ff_name )
-
- #else
-
- #define FILE_INFO struct find_t
- #define FIND_FIRST( n, i ) _dos_findfirst( (n), _A_SUBDIR, (i) )
- #define FIND_NEXT( info ) _dos_findnext( ( info ) )
- #define FILE_NAME( info ) ( ( info ).name )
-
- #endif
-
- void FatalError( char *fmt, ... );
- unsigned long CalculateFileCRC( FILE *file );
- void ProcessAllFiles( char *path, FILE *crc_file );
- void BuildCRCFile( char *input_dir_name, char *crc_file_name );
- void CheckFiles( char *crc_file_name );
- unsigned long CalculateBufferCRC( unsigned int count, unsigned long crc,
- void *buffer );
- void BuildCRCTable( void );
-
- #endif /* UNIX */
-
- /*
- * The main program is fairly simple. It checks for valid occurences
- * of the two different types of command lines, and executes them if
- * found. Otherwise, it prints out a simple usage statement and exits.
- */
-
- int main( argc, argv )
- int argc;
- char *argv[];
- {
- setbuf( stdout, NULL );
- BuildCRCTable();
- if ( argc == 2 )
- CheckFiles( argv[ 1 ] );
- else if ( argc == 4 && strcmp( argv[ 1 ], "-b" ) == 0 )
- BuildCRCFile( argv[ 2 ], argv[ 3 ] );
- else {
- printf( "Usage: CRCMAN [-b input_dir] crc-file \n" );
- printf( "\n" );
- printf( "Using the -b option checks all files under the input_dir\n" );
- printf( "and appends their data to the crc-file. Otherwise, the\n" );
- printf( "program checks the CRC data of all of the files in the\n" );
- printf( "crc-file and prints the results\n" );
- return( 1 );
- }
- return( 0 );
- }
-
- /*
- * Instead of performing a straightforward calculation of the 32 bit
- * CRC using a series of logical operations, this program uses the
- * faster table lookup method. This routine is called once when the
- * program starts up to build the table which will be used later
- * when calculating the CRC values.
- */
-
- #define CRC32_POLYNOMIAL 0xEDB88320L
-
- void BuildCRCTable()
- {
- int i;
- int j;
- unsigned long crc;
-
- for ( i = 0; i <= 255 ; i++ ) {
- crc = i;
- for ( j = 8 ; j > 0; j-- ) {
- if ( crc & 1 )
- crc = ( crc >> 1 ) ^ CRC32_POLYNOMIAL;
- else
- crc >>= 1;
- }
- CRCTable[ i ] = crc;
- }
- }
-
- /*
- * The routine to check the CRC values for a list of files has a
- * fairly easy job of it. It just reads in a line at a time from
- * the CRC file. Each line contains a file name and a CRC value.
- * The program then just has to calculate the actual CRC for that
- * file, and compare it with the current calculated value. Any
- * discrepancy triggers an error message.
- */
-
- void CheckFiles( crc_file_name )
- char *crc_file_name;
- {
- FILE *crc_file;
- FILE *test_file;
- unsigned long log_crc;
- unsigned long crc;
- char log_name[ FILENAME_SIZE ];
- int result;
-
- crc_file = fopen( crc_file_name, "r" );
- if ( crc_file == NULL )
- FatalError( "Couldn't open the log file: %s\n", crc_file_name );
- for ( ; ; ) {
- result = fscanf( crc_file, "%lx %s", &log_crc, log_name );
- if ( result < 2 )
- break;
- test_file = fopen( log_name, "rb" );
- if ( test_file != NULL ) {
- printf( "Checking %s ", log_name );
- crc = CalculateFileCRC( test_file );
- fclose( test_file );
- if ( crc != log_crc )
- printf( "Error: Expected %08lx, got %08lx\n",
- log_name, log_crc, crc );
- else
- printf( "OK\n" );
- } else
- printf( "Could not open file %s\n", log_name );
- }
- }
-
- /*
- * Building the CRC file is a little harder than just checking
- * the file values. This is because the build operation has to
- * parse through a directory tree, checking every file. This
- * routine defers the hard part of that to a routine called
- * ProcessAllFiles(), which takes care of scanning through the
- * directory. That means all we have to do here is open the output
- * CRC file, and then start the processing. This routine also makes
- * sure that the directory name passed on the command line is
- * stripped of any trailing '/' or '\' character, since people tend
- * to include those when specifying directory names.
- */
-
- void BuildCRCFile( input_dir_name, crc_file_name )
- char *input_dir_name;
- char *crc_file_name;
- {
- char path[ FILENAME_SIZE ];
- FILE *crc_file;
-
- strcpy( path, input_dir_name );
- if ( path[ strlen( path ) - 1 ] == SEPARATOR[ 0 ] )
- path[ strlen( path ) - 1 ] = '\0';
- crc_file = fopen( crc_file_name, "w" );
- if ( crc_file == NULL )
- FatalError( "Can't open crc log file: %s\n", crc_file_name );
- ProcessAllFiles( path, crc_file );
- }
-
- /*
- * This routine is responsible for actually performing the
- * calculation of the 32 bit CRC for the entire file. We
- * precondition the CRC value with all 1's, then invert every bit
- * after the entire file has been done. This gives us a CRC value
- * that corresponds with the values calculated by PKZIP and ARJ.
- * The actual calculation consists of reading in blocks from the
- * file, then updating the CRC with the value for that block. The
- * CRC work is done by another the CalculateBufferCRC routine.
- */
-
- unsigned long CalculateFileCRC( file )
- FILE *file;
- {
- unsigned long crc;
- int count;
- unsigned char buffer[ 512 ];
- int i;
-
- crc = 0xFFFFFFFFL;
- i = 0;
- for ( ; ; ) {
- count = fread( buffer, 1, 512, file );
- if ( ( i++ % 32 ) == 0 )
- putc( '.', stdout );
- if ( count == 0 )
- break;
- crc = CalculateBufferCRC( count, crc, buffer );
- }
- putc( ' ', stdout );
- return( crc ^= 0xFFFFFFFFL );
- }
-
- /*
- * This is the routine that is responsible for calculating all of
- * the CRC values for the files in a given directory. The CRC
- * values and the file names are written out to the crc_file. This
- * routine is somewhat ugly and hard to read because of all the
- * conditional code. When searching through directories under
- * MS-DOS and UNIX, the flow of control is identical, but all of the
- * function calls, structure names, and elements are different.
- *
- * This routine sits in a loop for each directory, opening each file
- * and processing it. Before a file is opened, a check is made to
- * see if the file is actually a directory. If it turns out that
- * the file is a directory, a new path name is constructed, and this
- * routine calls itself recursively so that all the files in the
- * subdirectory are also processed.
- */
-
- void ProcessAllFiles( path, crc_file )
- char *path;
- FILE *crc_file;
- {
- #ifdef UNIX
- DIR *dirp;
- #ifdef M_XENIX
- struct direct *entry;
- #else
- struct dirent *entry;
- #endif /* M_XENIX */
- #define NAME entry->d_name
- #else
- FILE_INFO fileinfo;
- int done;
- #define NAME FILE_NAME( fileinfo )
- #endif
- char fullname[ FILENAME_SIZE ];
- struct stat buf;
- unsigned long crc;
- FILE *file;
-
- printf( "Searching %s\n", path );
- strcat( path, SEPARATOR );
- #ifdef UNIX
- dirp = opendir( path );
- if ( dirp == NULL )
- FatalError( "Error opening directory %s\n", path );
- entry = readdir( dirp );
- while ( entry != 0 ) {
- #else
- strcpy( fullname, path );
- strcat( fullname, "*.*" );
- done = FIND_FIRST( fullname, &fileinfo );
- while ( done == 0 ) {
- #endif
- strcpy( fullname, path );
- if ( strcmp( NAME, "." ) && strcmp( NAME, ".." ) ) {
- strcat( fullname, NAME );
- if ( stat( fullname, &buf ) == -1 )
- FatalError( "Error reading stat from file %s!\n", fullname );
- if ( buf.st_mode & S_IFDIR )
- ProcessAllFiles( fullname, crc_file );
- else {
- file = fopen( fullname, "rb" );
- if ( file != NULL ) {
- printf( "Scanning %s ", fullname );
- crc = CalculateFileCRC( file );
- putc( '\n', stdout );
- fprintf( crc_file, "%08lx %s\n", crc, fullname );
- fclose( file );
- } else
- printf( "Could not open %s!\n", fullname );
- }
- }
- #ifdef UNIX
- entry = readdir( dirp );
- #else
- done = FIND_NEXT( &fileinfo );
- #endif
- }
- }
-
- /*
- * This routine calculates the CRC for a block of data using the
- * table lookup method. It accepts an original value for the crc,
- * and returns the updated value.
- */
-
- unsigned long CalculateBufferCRC( count, crc, buffer )
- unsigned int count;
- unsigned long crc;
- void *buffer;
- {
- unsigned char *p;
- unsigned long temp1;
- unsigned long temp2;
-
- p = (unsigned char*) buffer;
- while ( count-- != 0 ) {
- temp1 = ( crc >> 8 ) & 0x00FFFFFFL;
- temp2 = CRCTable[ ( (int) crc ^ *p++ ) & 0xff ];
- crc = temp1 ^ temp2;
- }
- return( crc );
- }
-
- /*
- * The fatal error handler just has to print out a formatted error
- * message and then exit. The difficulty in this routine lies in
- * the different way that variable numbers of arguments are
- * processed under ANSI C and K&R C. The body of the routine is
- * the same under both environments, but the declaration of the
- * function and its arguments differs quite a bit.
- */
-
- #ifdef UNIX
-
- void FatalError( va_alist )
- va_dcl
- {
- char *fmt;
- va_list argptr;
-
- va_start( argptr );
- fmt = va_arg( argptr, char * );
-
- #else
-
- void FatalError( char *fmt, ... )
- {
- va_list argptr;
- va_start( argptr, fmt );
-
- #endif
-
- printf( "Fatal error: " );
- vprintf( fmt, argptr );
- va_end( argptr );
- exit( -1 );
- }
- /************************** End of CRCMAN.C ****************************/
-
-